package com.sakura.probe.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.sakura.probe.common.api.CommonResult;
import com.sakura.probe.common.util.JwtTokenUtil;
import com.sakura.probe.common.util.StringEncoder;
import com.sakura.probe.nosql.elasticsearch.EsSearchService;
import com.sakura.probe.nosql.redis.RedisKey;
import com.sakura.probe.nosql.redis.RedisService;
import com.sakura.probe.pojo.FootPrint;
import com.sakura.probe.pojo.PersonInfo;
import com.sakura.probe.pojo.Topic;
import com.sakura.probe.pojo.TopicCategory;
import com.sakura.probe.service.FootPrintService;
import com.sakura.probe.service.OssService;
import com.sakura.probe.service.TopicCategoryService;
import com.sakura.probe.service.TopicService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;

@Api(tags = "TopicManagementController",description = "发布和编辑以及显示帖子")
@Controller
@Slf4j
@RequestMapping("/topic")
public class TopicController {
    @Autowired
    private TopicCategoryService topicCategoryService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private TopicService topicService;
    @Autowired
    private EsSearchService esSearchService;
    @Autowired
    private FootPrintService footPrintService;
    @Autowired
    private OssService ossService;

    //视频最大上传量
    final long MAX_VIDEO_SIZE = 1024*1024*500;

    //支持上传图片的最大数量
    private static final int IMAGEMAXCOUNT = 6;


    @ApiOperation("获取话题类型")
    @ResponseBody
    @GetMapping(value = "/getTopicCategory")
    public CommonResult<List<TopicCategory>> getTopicCategory(){
        List<TopicCategory> list = topicCategoryService.getTopicCategoryList();
        return list==null?CommonResult.failed():CommonResult.success(list);
    }

    @ApiOperation("获取发布内容的信息以及图片,并存入数据库中")
    @ResponseBody
    @PostMapping(value = "/publishTopic")
    @RequiresRoles(logical = Logical.OR,value = {"0","1","2","3"})
    public CommonResult publishTopic(HttpServletRequest request,int type, String topicStr,String token,Integer head){
        List<MultipartFile> fileList = new ArrayList<>();
        Topic topic = null;
        MultipartFile video;
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
        //接收前端参数的变量的初始化
        ObjectMapper mapper = new ObjectMapper();
        MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
        if (type==1){
            //上传图片
            //若请求中存在文件流,则取出相关的文件
            try {
                if(multipartResolver.isMultipart(request)){
                    getTopicImgList(multiRequest,fileList);
                }
            } catch (Exception e) {
                return CommonResult.failed(e.getMessage());
            }
        }else {
            try {
                //上传视频
                if (multipartResolver.isMultipart(request)){
                    video = multiRequest.getFile("video");
                    if (video.getSize()>MAX_VIDEO_SIZE){
                        return CommonResult.failed("上传的视频最大不能超过500M");
                    }else if (video.getOriginalFilename().indexOf(".mp4")<0){
                        return CommonResult.failed("视频上传格式只支持mp4");
                    }
                    fileList.add(video);
                }
            } catch (Exception e) {
                return CommonResult.failed(e.getMessage());
            }
        }
        try {
            //尝试获取前端传过来的表单string流并将其转换成Topic实体类
            topic = mapper.readValue(topicStr, Topic.class);
        } catch (IOException e) {
            return CommonResult.failed(e.getMessage());
        }
        if (topic!=null&&!topic.getTopicName().equals("")){
            //从redis中获取用户信息
            PersonInfo person = redisService.getPersonByToken(token);
            //将正文的换行符转换成<br/>
            topic.setOwnerId(person.getUserId()).setPersonInfo(person)
                    .setTopicDesc(StringEncoder.inDatabase(topic.getTopicDesc()));
            if (null!=head){
                topic.setEnableHeadline(head);
            }
            log.info("topic="+topic.toString());
            //调用service方法进行添加
            return topicService.save(topic,fileList,type);
        }else {
            return CommonResult.failed("信息未填写完整");
        }
    }

    @ApiOperation("返回话题列表页中对应的列表信息")
    @ResponseBody
    @GetMapping(value = "/topicListInfo")
    public Map<String,Object> TopicListInfo(int pageIndex,int pageSize,boolean type,
                                      Long topicCategoryId,String topicName){
        HashMap<String,Object> modelMap = new HashMap<>();
        Topic condition = new Topic(topicCategoryId,topicName);
        condition.setDeleted(0);
        CommonResult<List<Topic>> res;
        if (type){
            res = esSearchService.getTopicList(condition, pageIndex, pageSize);
        }else {
            res = topicService.listByCondition(condition, pageIndex, pageSize);
        }
        modelMap.put("result",res);
        modelMap.put("count",topicService.countByCondition(condition));
        modelMap.put("success",true);
        return modelMap;
    }

    @ApiOperation("根据话题id获取帖子正文内容")
    @ResponseBody
    @GetMapping("/getTopicInfo")
    public CommonResult<Topic> TopicInfo(Long topicId,String token){
        return topicService.getTopicInfo(topicId,JwtTokenUtil.getUsernameFromToken(token));
    }


    /**
     * 由于点赞和收藏存在高并发的问题,因此先将对应的信息(即是点赞还是取消点赞)加入到redis中做为缓存
     * 再设置一个定时器,每间隔一段时间就从redis中取出对应的数据
     * 简单地来说就是redis 异步入库，就是点赞和取消都交给 redis，redis 记录了点赞人和被点赞人，
     * 同时在另外记录点赞总数，然后通过定时任务进行异步落库并删除 redis 中的指定数据。
     *
     * 关于在不使用mysql存储用户点赞和收藏操作时,如何标识用户是否对该话题进行点赞和收藏的
     * 这里我统一使用redis进行存储用户对话题的点赞和收藏信息
     * key使用PersonThumb_userId , value使用set集合来存储用户点赞话题的id
     * @param topicId 需要操作的话题id
     * @param type  true-点赞 false-收藏
     */
    @ApiOperation("为帖子(添加/取消)点赞或收藏")
    @ResponseBody
    @GetMapping("/thumbOrCollect")
    @RequiresRoles(logical = Logical.OR,value = {"0","1","2","3"})
    public synchronized CommonResult thumbOrCollect(String topicId,boolean type,
                                                     HttpServletRequest request){
        String userId = JwtTokenUtil.getUsernameFromToken(request.getHeader("Token"));
        try {
            String topicKey = type?RedisKey.getThumbTopicIdList():RedisKey.getCollectTopicIdList();
            String personKey = type?RedisKey.getPersonThumb():RedisKey.getPersonCollect();
            //获取该用户点赞(收藏)的列表
            Set<String> personSet = redisService.getSet(personKey + userId);
            if (null==personSet||!personSet.contains(topicId)){
                //说明该用户没有对该话题进行点赞(收藏)
                if (null==personSet){
                    personSet = new HashSet<>();
                }
                //在对应列表中添加上该话题id
                personSet.add(topicId);
                //并且将该帖子的点赞(收藏)量加一
                redisService.increment(topicKey+topicId,1);
            }else if (personSet.contains(topicId)){
                //说明该用户之前已经对该话题进行了点赞(收藏)
                personSet.remove(topicId);
                //并且将该帖子的信息点赞(收藏)量减一
                redisService.decrement(topicKey+topicId,1);
            }
            //重新添加到redis中
            redisService.setSet(personKey + userId,personSet);
        } catch (Exception e) {
            return CommonResult.failed(e.getMessage());
        }
        return CommonResult.success(null);
    }

    /**
     * 当用户浏览当前话题时先从redis中取出当前用户的浏览记录
     * 如果当前话题为第一次访问则将信息缓存到redis中并且将相关信息存储在mysql中
     * redis在其中起到判断用户是否第一次浏览该话题
     */
    @ApiOperation("每当浏览当前话题时更新当前用户的浏览记录")
    @ResponseBody
    @GetMapping("/addFootPrint")
    @RequiresRoles(logical = Logical.OR,value = {"0","1","2","3"})
    public CommonResult addFootPrint(HttpServletRequest request,Long topicId){
        String token = request.getHeader("Token");
        Long userId = Long.valueOf(JwtTokenUtil.getUsernameFromToken(token));
        FootPrint footPrint = new FootPrint(userId,topicId);
        //先判断该用户是否是第一次浏览该话题
        String key = RedisKey.getPerson_FootPrint()+userId;
        Set<String> personSet = redisService.getSet(key);
        if (null==personSet){
            //表示该用户是第一次访问该话题
            personSet = new HashSet<>();
            footPrintService.save(footPrint);
            personSet.add(userId+"");
        }else {
            //表示该用户不是第一次访问该话题
            footPrintService.updateById(footPrint);
        }
        redisService.setSet(key,personSet);
        return CommonResult.success(null);
    }

    private void getTopicImgList(MultipartHttpServletRequest request, List<MultipartFile> topicImgList) {
        MultipartHttpServletRequest multiRequest = request;
        //取出图片列表并构建List<CommonsMultipartFile>列表对象,最多支持六张图片上传
        for(int i=0;i<IMAGEMAXCOUNT;i++){
            CommonsMultipartFile topicImgFile = (CommonsMultipartFile) multiRequest.getFile("topicImg"+i);
            if (topicImgFile!=null){
                System.out.println("图片的大小:"+topicImgFile.getSize());
                //若取出的第i个详情图片文件流不为空,则将其加入list集合中
                topicImgList.add(topicImgFile);
            }else {
                break;
            }
        }
    }
}
